<?php
namespace Teemo;

/**
 * 框架主文件
 * Created by PhpStorm.
 * User: lkk
 * Date: 2019/1/14
 * Time: 2:32 PM
 */

use Teemo\Core\Config;
use Teemo\Core\Route;
use Teemo\Core\Log;
use Teemo\Coroutine\Context;
use Teemo\Coroutine\Coroutine;
use Swoole;

class Teemo
{

    /**
     * @var 根目录
     */
    public static $rootPath;
    /**
     * @var 框架目录
     */
    public static $frameworkPath;
    /**
     * @var 扩展目录
     */
    public static $vendorPath;
    /**
     * @var 程序目录
     */
    public static $applicationPath;

    final public static function run()
    {
        // start
        if (!defined('DS')) {
            define('DS', DIRECTORY_SEPARATOR);
        }
        if (!defined('APP_NAME')) {
            define('APP_NAME', 'application');
        }
        /*define('__ROOT__', dirname(dirname(__DIR__)));
        define('__FRAMEWORK__', __ROOT__ . DS . 'framework');
        define('__APP__', __ROOT__ . DS . APP_NAME);*/
        self::$rootPath        = dirname(dirname(__DIR__));
        self::$frameworkPath   = self::$rootPath . DS . 'framework';
        self::$applicationPath = self::$rootPath . DS . 'application';
        self::$vendorPath      = self::$rootPath . DS . 'vendor';


        // regeister
        \spl_autoload_register(__CLASS__ . '::autoLoader');


        // load config
        Config::load();


        $timeZone = Config::get('time_zone', 'Asia/Shanghai');
        \date_default_timezone_set($timeZone);


        $http = new Swoole\Http\Server(Config::get('host'), Config::get('port'));
        $http->set(['worker_num' => Config::get('worker_num'),]);


        // worker_start
        $http->on('workerStart', function (\swoole_http_server $serv, $worker_id) {

            print_r(get_included_files());

            if (function_exists('apcache_reset')) {
                \opcache_reset(); //清除opcache 缓存，swoole模式下其实可以关闭opcache
            }

            try {
                //加载配置，让此处加载的配置可热更新
                Config::loadLazy();
                //日志初始化
                Log::init();
                //配置了mysql, 初始化mysql连接池
                $mysqlConfig = Config::get('mysql');
                if ($mysqlConfig) {
                    Pool\Mysql::getInstance($mysqlConfig);
                }
            } catch (\Exception $e) {
                //print_r($e);
                $serv->shutdown();
            } catch (\Error $r) {
                print_r($r->getMessage());
                $serv->shutdown();
            } catch (\Throwable $t) {
                //print_r($t);
                $serv->shutdown();
            }
        });

        $http->on('start', function (\swoole_server $serv) {
            //服务启动
            //日志初始化
            Log::init();
            file_put_contents(self::$rootPath . DS . 'bin' . DS . 'master.pid', $serv->master_pid);
            file_put_contents(self::$rootPath . DS . 'bin' . DS . 'manager.pid', $serv->manager_pid);
            Log::info("http server start! {host}: {port}, masterId:{masterId}, managerId: {managerId}", [
                '{host}' => Config::get('host'),
                '{port}' => Config::get('port'),
                '{masterId}' => $serv->master_pid,
                '{managerId}' => $serv->manager_pid,
            ]);
        });

        $http->on('shutdown', function () {
            //服务关闭，删除进程id
            unlink(self::$rootPath . 'DS' . 'bin' . DS . 'master.pid');
            unlink(self::$rootPath . 'DS' . 'bin' . DS . 'manager.pid');
            Log::info("http server shutdown");
        });


        // request
        $http->on('request', function (\swoole_http_request $request, \swoole_http_response $response) {

            // 浏览器自动发起请求处理
            if ($request->server['path_info'] == '/favicon.ico') {
                $response->end('');
                return;
            }

            try {
                $coId    = Coroutine::setBaseId();// 初始化根协程ID
                $context = new Context($request, $response);//初始化上下文
                Pool\Context::getInstance()->put($context);
                // 协程退出、自动清空
                defer(function () use ($coId) {
                    Pool\Context::getInstance()->release();
                });

                // route
                $result = Route::dispatch($request->server['path_info']);
                $response->end($result);
            } catch (\Exception $e) {
                Log::alert($e->getMessage(), $e->getTrace());
                $response->status('500');
            } catch (\Error $r) {
                Log::emergency($r->getMessage(), $r->getTrace());
                $response->status('500');
            } catch (\Throwable $t) {
                Log::emergency($t->getMessage(), $t->getTrace());
                $response->status('500');
            }
        });

        $http->start();
    }

    final public static function autoLoader($class)
    {
        // class Path
        $classPath = \str_replace('\\', DS, $class) . '.php';

        $findPath = [
            self::$frameworkPath . DS,
            self::$applicationPath . DS,
            self::$vendorPath . DS,
        ];

        // find class
        foreach ($findPath as $path) {
            $realPath = $path . $classPath;
            echo $realPath.PHP_EOL;
            if (is_file($realPath)) {
                require "{$realPath}";
                return;
            }
        }
    }

}
